use std::ops::RangeInclusive;

use clap::Parser;
use identitycard::{generate_identitycard, get_loc_code};
use regex::Regex;

fn region_validate(region: &str) -> Result<String, String> {
    let re = Regex::new(r"^[1-68][1-9][0-9]?[1-9]?[0-9]?[1-9]?$").unwrap();
    if re.is_match(region) {
        return Ok(region.to_string());
    } else if region.len() > 0 {
        return get_loc_code(region);
    } else {
        return Ok("".to_string());
    }
}

const COUNT_RANGE: RangeInclusive<usize> = 1..=65535;

fn count_validate(count: &str) -> Result<u16, String> {
    let c: usize = count
        .parse()
        .map_err(|_| format!("`{}` 不是一个数字", count))?;

    if COUNT_RANGE.contains(&c) {
        Ok(c as u16)
    } else {
        Err(format!(
            "生成数量必须在 {}-{}",
            COUNT_RANGE.start(),
            COUNT_RANGE.end()
        ))
    }
}

fn birthday_validate(b: &str) -> Result<String, String> {
    let re = Regex::new(r"^\d{4}(\d{2})?(\d{2})?$").unwrap();
    if re.is_match(b) {
        Ok(b.to_string())
    } else {
        Err("生日格式错误".to_string())
    }
}

#[derive(Debug, Parser)]
#[clap(author, version, about="随机生成身份证号", long_about = None)]
struct App {
    #[clap(
        short,
        long,
        value_parser = region_validate,
        help = "地区编号 全国行政区划编码:  http://www.mca.gov.cn//article/sj/xzqh/2020/2020/20200908007001.html"
    )]
    region: Option<String>,
    #[clap(short, long, value_parser=birthday_validate, help = "生日 eg: yyyymmdd ")]
    birthday: Option<String>,
    #[clap(short, long, value_parser=count_validate, default_value = "1", help = "生成数量")]
    count: u16,
    #[clap(long, value_parser, default_value = "false", help = "是否不显示索引")]
    no_index: bool,
}

fn main() {
    let args: App = App::parse();

    let region = args.region.unwrap_or(String::new());
    let birthday = args.birthday.unwrap_or(String::new());
    for idx in 1..(args.count + 1) {
        let rng_ic = generate_identitycard(region.clone(), birthday.clone());
        if !args.no_index {
            println!("{:3}. {}", idx, rng_ic);
        } else {
            println!("{}", rng_ic);
        }
    }
}
